package cn.zhouyafeng.itchat4j.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	// 翻墙代理IP
	private String proxyHost = "127.0.0.1";

	// 翻墙代理端口
	private int proxyPort = 1080;

	private CloseableHttpClient httpClient = HttpClients.createDefault();

	protected RequestConfig requestConfig;

	private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 1000 * 5;

	private static final int DEFAULT_CONNECT_TIMEOUT = 1000 * 5;

	private static final int DEFAULT_SOCKET_TIMEOUT = 1000 * 20;

	public Builder getBuilder() {
		return builder;
	}

	protected Builder builder = RequestConfig.custom();

	public HttpClientUtil() {
		builder.setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT);
		builder.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
		builder.setSocketTimeout(DEFAULT_SOCKET_TIMEOUT);
		requestConfig = builder.build();
	}

	public HttpClientUtil(int timeout) {
		builder.setConnectionRequestTimeout(timeout);
		builder.setConnectTimeout(timeout);
		builder.setSocketTimeout(timeout);
		requestConfig = builder.build();
	}

	public HttpClientUtil(boolean enableProxy) {
		if (enableProxy) {
			builder.setProxy(new HttpHost(proxyHost, proxyPort));
			requestConfig = builder.build();
		} else {
			requestConfig = builder.build();
		}
	}

	public HttpClientUtil(String proxyHost, int proxyPort) {
		this.proxyHost = proxyHost;
		this.proxyPort = proxyPort;
		builder.setProxy(new HttpHost(proxyHost, proxyPort));
		requestConfig = builder.build();
	}

	public JSONObject post(String uri, Map<String, String> headers, Map<String, String> params)
			throws Exception {
		logger.info("uri={}, params={}", uri, params);

		HttpPost httpPost = new HttpPost(uri);

		// 必须设置下面这个Header
		if(headers != null && headers.size() > 0){
			for (String key : headers.keySet()) {
				httpPost.addHeader(key,headers.get(key));
			}
		}

		List<NameValuePair> nameValuesPairs = new ArrayList<NameValuePair>();
		if (params != null) {
			for (String key : params.keySet()) {
				Object value = params.get(key);
				if (value != null) {
					NameValuePair nameValuePair = new BasicNameValuePair(key, params.get(key).toString());
					nameValuesPairs.add(nameValuePair);
				}
			}
		}

		CloseableHttpResponse response = null;
		HttpEntity requetEntity = new UrlEncodedFormEntity(nameValuesPairs, "utf8");
		httpPost.setEntity(requetEntity);
		httpPost.setConfig(requestConfig);
		try {
			response = httpClient.execute(httpPost);
			if (response.getStatusLine().getStatusCode() != 200) {
				httpPost.abort();
				logger.error("请求异常：response={}", JSONObject.toJSONString(response));
				throw new Exception(String.format("http请求出错，url=%s", uri));
			}
			String content = EntityUtils.toString(response.getEntity());
			EntityUtils.consume(response.getEntity());
			if (StringUtils.isBlank(content)) {
				logger.error("请求返回结果为空, uri={}, params={}", uri, params);
				return null;
			}
			return JSON.parseObject(content);
		} catch (Exception e) {
			throw new Exception(String.format("http请求出错，url=%s", uri));
		} finally {
			if (response != null) {
				response.close();
			}
		}

	}

	public JSONObject get(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
		//添加参数
		StringBuffer URL = new StringBuffer(url);
		if(params != null && params.size() > 0){
			URL.append("?");
			for (String key : params.keySet()) {
//				url += (key + "=" + URLEncoder.encode(params.get(key), "utf-8") + "&");
				URL.append(key).append("=").append(URLEncoder.encode(params.get(key), "utf-8")).append("&");
			}
			url = URL.substring(0, URL.length() - 1);

		}
		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(requestConfig);

		// 必须设置下面这个Header
		if(headers != null && headers.size() > 0){
			for (String key : headers.keySet()) {
				httpGet.addHeader(key,headers.get(key));
			}
		}

		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpGet);
			if (response.getStatusLine().getStatusCode() != 200) {
				logger.error("请求异常：statueLine={}, response={}", response.getStatusLine(), response);
				httpGet.abort();
				throw new Exception(String.format("http请求出错，url=%s", url));
			}

			String content = EntityUtils.toString(response.getEntity());
			EntityUtils.consume(response.getEntity());
			if (StringUtils.isBlank(content)) {
				logger.error("请求返回结果为空, uri={}, params={}", url, params);
				throw new Exception("请求返回结果为空");
			}
			return JSON.parseObject(content);
		} catch (Exception e) {
			throw new Exception(String.format("http请求出错，url=%s", url));
		} finally {
			if (response != null) {
				response.close();
			}
		}
//		throw new Exception("请求失败");
	}

	public <T> T get(String uri, Map<String, Object> params, TypeReference<T> typeReference, Feature... features)
			throws Exception {
		logger.info("http uri={}, params={}", uri, params);
		if (!uri.contains("?") && params != null && CollectionUtils.isNotEmpty(params.keySet())) {
			uri += '?';
		}
		if (params != null && CollectionUtils.isNotEmpty(params.keySet())) {
			for (String key : params.keySet()) {
				Object value = params.get(key);
				if (value == null) {
					continue;
				}
				if (uri.endsWith("?")) {
					uri += key + "=" + URLEncoder.encode(params.get(key).toString(), "utf8");
				} else {
					uri += "&" + key + "=" + URLEncoder.encode(params.get(key).toString(), "utf8");
				}
			}
		}
		HttpGet httpGet = new HttpGet(uri);
		httpGet.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpGet);
			if (response.getStatusLine().getStatusCode() != 200) {
				logger.error("请求异常：statueLine={}, response={}", response.getStatusLine(), response);
				httpGet.abort();
				throw new Exception(String.format("http请求出错，url=%s", uri));
			}

			String content = EntityUtils.toString(response.getEntity());
			EntityUtils.consume(response.getEntity());
			if (StringUtils.isBlank(content)) {
				logger.error("请求返回结果为空, uri={}, params={}", uri, params);
				return null;
			}
			T result = JSON.parseObject(content, typeReference, features);
			return result;
		} catch (Exception e) {
			throw new Exception(String.format("http请求出错，url=%s", uri));
		} finally {
			if (response != null) {
				response.close();
			}
		}

	}

	public <T> T post(String uri, Map<String, Object> params, TypeReference<T> typeReference, Feature... features)
			throws Exception {
		logger.info("uri={}, params={}", uri, params);
		HttpPost httpPost = new HttpPost(uri);
		List<NameValuePair> nameValuesPairs = new ArrayList<NameValuePair>();
		if (params != null) {
			for (String key : params.keySet()) {
				Object value = params.get(key);
				if (value != null) {
					NameValuePair nameValuePair = new BasicNameValuePair(key, params.get(key).toString());
					nameValuesPairs.add(nameValuePair);
				}
			}
		}

		CloseableHttpResponse response = null;
		HttpEntity requetEntity = new UrlEncodedFormEntity(nameValuesPairs, "utf8");
		httpPost.setEntity(requetEntity);
		httpPost.setConfig(requestConfig);
		try {
			response = httpClient.execute(httpPost);
			if (response.getStatusLine().getStatusCode() != 200) {
				httpPost.abort();
				logger.error("请求异常：response={}", JSONObject.toJSONString(response));
				throw new Exception(String.format("http请求出错，url=%s", uri));
			}
			String content = EntityUtils.toString(response.getEntity());
			EntityUtils.consume(response.getEntity());
			if (StringUtils.isBlank(content)) {
				logger.error("请求返回结果为空, uri={}, params={}", uri, params);
				return null;
			}
			T result = JSON.parseObject(content, typeReference, features);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception(String.format("http请求出错，url=%s", uri));
		} finally {
			if (response != null) {
				response.close();
			}
		}

	}

	public String postWithJson(String uri, Map<String, Object> requestHeader, String jsonParams) throws Exception {
		logger.info("uri={}, jsonParams={}", uri, jsonParams);
		HttpPost httpPost = new HttpPost(uri);

		CloseableHttpResponse response = null;
		StringEntity entity = new StringEntity(jsonParams);
		httpPost.setEntity(entity);

		if (!org.springframework.util.CollectionUtils.isEmpty(requestHeader)) {
			for (String key : requestHeader.keySet()) {
				httpPost.setHeader(key, requestHeader.get(key) + "");
			}
		}
		httpPost.setConfig(requestConfig);
		try {
			response = httpClient.execute(httpPost);
			if (response.getStatusLine().getStatusCode() != 200) {
				httpPost.abort();
				throw new Exception(String.format("http请求出错，url=%s", uri));
			}
			String content = EntityUtils.toString(response.getEntity());
			EntityUtils.consume(response.getEntity());
			if (StringUtils.isBlank(content)) {
				logger.error("请求返回结果为空, uri={}, jsonParams={}", uri, jsonParams);
				return null;
			}

			return content;
		} catch (Exception e) {
			throw new Exception(String.format("http请求出错，url=%s", uri));
		} finally {
			if (response != null) {
				response.close();
			}
		}

	}

	public <T> T getToUTF8(String uri, Map<String, Object> params, TypeReference<T> typeReference, Feature... features)
			throws Exception {
		logger.info("http uri={}, params={}", uri, params);
		if (!uri.contains("?") && params != null && CollectionUtils.isNotEmpty(params.keySet())) {
			uri += '?';
		}
		if (params != null && CollectionUtils.isNotEmpty(params.keySet())) {
			for (String key : params.keySet()) {
				Object value = params.get(key);
				if (value == null) {
					continue;
				}
				if (uri.endsWith("?")) {
					uri += key + "=" + URLEncoder.encode(params.get(key).toString(), "utf8");
				} else {
					uri += "&" + key + "=" + URLEncoder.encode(params.get(key).toString(), "utf8");
				}
			}
		}
		HttpGet httpGet = new HttpGet(uri);
		httpGet.setConfig(requestConfig);
		httpGet.setHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8");
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpGet);

			if (response.getStatusLine().getStatusCode() != 200) {
				logger.error("请求异常：statueLine={}, response={}", response.getStatusLine(), response);
				httpGet.abort();
				throw new Exception(String.format("http请求出错，url=%s", uri));
			}

			String content = EntityUtils.toString(response.getEntity(), "UTF-8");
			EntityUtils.consume(response.getEntity());
			if (StringUtils.isBlank(content)) {
				logger.error("请求返回结果为空, uri={}, params={}", uri, params);
				return null;
			}
			T result = JSON.parseObject(content, typeReference, features);
			return result;
		} catch (Exception e) {
			throw new Exception(String.format("http请求出错，url=%s", uri));
		} finally {
			if (response != null) {
				response.close();
			}
		}

	}
}
